package chen.yi.component.data.desensitization.interceptor;

import chen.yi.component.data.desensitization.annotation.SensitiveData;
import chen.yi.component.data.desensitization.annotation.SensitiveField;
import chen.yi.component.data.desensitization.decryption.DataDecryption;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Properties;

/**
 * 出参解密拦截器
 * @author huat
 **/
@Intercepts(
        @Signature(type = ResultSetHandler.class,method = "handleResultSets",args = {Statement.class})
)
@Component
public class DecryptInterceptor implements Interceptor {
    private final DataDecryption decrypt;

    @Autowired
    public DecryptInterceptor(DataDecryption decrypt) {
        this.decrypt = decrypt;
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //取出查询的结果
        Object resultObject = invocation.proceed();
        if (Objects.isNull(resultObject)) {
            return null;
        }
        //基于返回结果为List类型的
        if (resultObject instanceof ArrayList) {
            ArrayList resultList = (ArrayList) resultObject;
            if (!CollectionUtils.isEmpty(resultList) && needToDecrypt(resultList.get(0))) {
                for (Object result : resultList) {
                    decrypt(result);
                }
            }
            //基于selectOne
        } else {
            if (needToDecrypt(resultObject)) {
                decrypt(resultObject);
            }
        }
        return resultObject;
    }

    /**
     * 判断注解是否为 SensitiveData
     * @param object
     * @return
     */
    private boolean needToDecrypt(Object object) {
        Class<?> objectClass = object.getClass();
        SensitiveData sensitiveData = AnnotationUtils.findAnnotation(objectClass, SensitiveData.class);
        return Objects.nonNull(sensitiveData);
    }

    /**
     * 逐个解密密字段
     * @param result
     * @return
     */
    private Object decrypt(Object result) throws IllegalAccessException {
        Class<?> resultClass = result.getClass();
        Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : declaredFields) {
            //取出所有被EncryptDecryptField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (!Objects.isNull(sensitiveField)) {
                field.setAccessible(true);
                Object object = field.get(result);
                //将解密后的数据保存到字段上
                field.set(result, decrypt.decrypt(object));
            }
        }
        return result;

    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}
